package gardienapplet.net;

import java.io.*;
import java.net.*;
import java.util.*;
import net.hangar5.xmlrpc.*;
import superviseur.ihm.gardien.*;

public class Superviseur implements CdeGardien
{
    private static final int minWorkers = 4;  // these are the TINI values, for full scale JVMs the value should be larger
    private static final int maxWorkers = 8;  // these are the TINI values, for full scale JVMs the value should be larger
    private static final int maxKeepAlives = 6;  // these are the TINI values, for full scale JVMs the value should be larger
    private static final int workerIdleLife = 120000; // two minutes
    private static final int socketReadTimeout = 120000; // two minutes

    //serveur RPC
    private  RpcServer server;
    private  Thread threadServer;
    private int portServer;

    // client RPC
    private RpcClient client;
    private String urlSuperviseur;
    private String myUrl;
    private Gardien gardien;

    public Superviseur(String urlSuperviseur, int portServer, String myAdresseIP) throws Exception
    {
	if (portServer > 0) this.portServer = portServer;
	myUrl = "http://" + myAdresseIP + ":" + portServer;
	this.gardien = new Gardien(this);

	// creation du server
	try
	{
	    ServerSocket ss = new ServerSocket(this.portServer);
	    server = new RpcServer( ss , minWorkers, maxWorkers, maxKeepAlives, workerIdleLife, socketReadTimeout);
	    Dispatcher dispatcher = server.getDispatcher();
	    //dispatcher.setVerbose(false);
	    addMethods(dispatcher);
	    threadServer = new Thread(server);
	    threadServer.setDaemon(false);
	    threadServer.start();
	}
	catch (Exception e)
	{
	    System.out.println("creation server impossible: " + e.getMessage());
	}

	// creation du client
	client = new RpcClient();
	client.setKeepAlive(false);
	setURLSuperviseur(urlSuperviseur);
	if (registerGardien(myUrl, true))
	   gardien.setStateBorne(getStateBornes());
	   else gardien.setStateBorne(null);
    }

    public void shutDown(final int delay)
    {
	try
	{
	    registerGardien(myUrl, false);
	}
	catch (Exception e) {e.printStackTrace();}
	try
	{
	    server.shutDown();
	}
	catch (IOException io) {io.printStackTrace();}
	while (threadServer.isAlive()){};
	gardien.stop();
    }

    public String getUrlSuperviseur()
    {
	return urlSuperviseur;
    }

    // Definir URL du client
    public boolean setURLSuperviseur(String url)
    {
	boolean result = true;
	try
	{
	    client.setUrl(url);
	    urlSuperviseur = url;
	}
	catch (Exception other)
	{
	    urlSuperviseur = null;
	    result = false;
	    System.err.println ("Exception in client: "+other);
	    other.printStackTrace();
	}
	return result;
    }

    //ajouter methodes au serveur
    private void addMethods( Dispatcher dispatcher )
    {
	IMethod m;
	m = new AddBorne();
	dispatcher.addMethod( m );
	m = new SuppBorne();
	dispatcher.addMethod( m );
	m = new SupAllBornes();
	dispatcher.addMethod( m );
	m = new SelectBorne();
	dispatcher.addMethod( m );
	m = new SetNombreVehiculesMax();
	dispatcher.addMethod( m );
	m = new SetNombreVehicules();
	dispatcher.addMethod( m );
	m = new DoPassage();
	dispatcher.addMethod( m );
	m = new DoAppel();
	dispatcher.addMethod( m );
	m = new Alarme();
	dispatcher.addMethod( m );
	m = new DefautBorne();
	dispatcher.addMethod( m );
	m = new SetBoutonEclairage();
	dispatcher.addMethod( m );
	m = new DoAfficheAutorisation();
	dispatcher.addMethod( m );
    }

    //****************************************************************************
    // methodes en provenance de ParkingCenter
    //****************************************************************************
/*
    public class ShutDown extends Method
    {
	private static final String strName = "shutDown";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    int ret = -1;
	    Integer oRet;
	    if (accesParking.canExit()) ret = 0;
	    oRet = new Integer(ret);
	    if (ret == 0)
	    {
		Thread t = new Thread()
		{
		    public void run()
		    {
			accesParking.shutDown();
		    }
		};
		t.start();
	    }
	    return oRet;
	}
    }
    */
    private class AddBorne extends Method
    {
	private static final String strName = "addBorne";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		String nomBorne = (String)vParams.elementAt(0);
		int numBorne = ((Integer)vParams.elementAt(1)).intValue();
		gardien.addBorne(nomBorne, numBorne);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class SuppBorne extends Method
    {
	private static final String strName = "suppBorne";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		int numBorne = ((Integer)vParams.elementAt(0)).intValue();
		gardien.supBorne(numBorne);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class SupAllBornes extends Method
    {
	private static final String strName = "supAllBornes";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		gardien.supAllBornes();
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class SelectBorne extends Method
    {
	private static final String strName = "selectBorne";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		int numBorne = ((Integer)vParams.elementAt(0)).intValue();
		gardien.selectBorne(numBorne);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class SetNombreVehiculesMax extends Method
    {
	private static final String strName = "setNombreVehiculesMax";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		int n = ((Integer)vParams.elementAt(0)).intValue();
		gardien.setNombreVehiculesMax(n);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class SetNombreVehicules extends Method
    {
	private static final String strName = "setNombreVehicules";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		int n = ((Integer)vParams.elementAt(0)).intValue();
		gardien.setNombreVehicules(n);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class DoPassage extends Method
    {
	private static final String strName = "doPassage";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		int numBorne = ((Integer)vParams.elementAt(0)).intValue();
		int nombreVehicules = ((Integer)vParams.elementAt(1)).intValue();
		boolean entree = ((Boolean)vParams.elementAt(2)).booleanValue();
		gardien.doPassage(numBorne, nombreVehicules, entree);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class DoAppel extends Method
    {
	private static final String strName = "doAppel";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		int numBorne = ((Integer)vParams.elementAt(0)).intValue();
		boolean on = ((Boolean)vParams.elementAt(1)).booleanValue();
		gardien.doAppel(numBorne, on);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class DoAfficheAutorisation extends Method
    {
	private static final String strName = "doAffAut";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		int numBorne = ((Integer)vParams.elementAt(0)).intValue();
		boolean on = ((Boolean)vParams.elementAt(1)).booleanValue();
		gardien.doAfficheAutorisation(numBorne, on);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class Alarme extends Method
    {
	private static final String strName = "alarme";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {

		boolean on = ((Boolean)vParams.elementAt(0)).booleanValue();
		String nomBorne = (String)vParams.elementAt(1);
		int numBorne = ((Integer)vParams.elementAt(2)).intValue();
		gardien.alarme(on, nomBorne, numBorne);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class DefautBorne extends Method
    {
	private static final String strName = "defautBorne";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		boolean on = ((Boolean)vParams.elementAt(0)).booleanValue();
		int numBorne = ((Integer)vParams.elementAt(1)).intValue();
		String codeDefaut = (String)vParams.elementAt(2);
		gardien.setDefautBorne(on, numBorne, codeDefaut);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    private class SetBoutonEclairage extends Method
    {
	private static final String strName = "setBoutonEclairage";
	public String getName()
	{
	    return strName;
	}

	public Object execute(Vector vParams) throws RpcException
	{
	    Object oRet;
	    try
	    {
		boolean on = ((Boolean)vParams.elementAt(0)).booleanValue();
		gardien.setBoutonEclairage(on);
		oRet = new Boolean(true);
	    }
	    catch( ClassCastException x )
	    {
		oRet = null;
		throw new RpcException( RpcException.BADPARAMTYPE );
	    }
	    return oRet;
	}
    }

    //*****************************************************************************
    //*****************************************************************************

    public boolean registerGardien(String myUrl, boolean on)
    {
	boolean resultat = false;
	final String methode = "registerGardien";
	Vector v = new Vector();
	v.addElement(new Boolean(on));
	v.addElement(myUrl);
	try
	{
	    Object result = client.execute(methode, v);
	    resultat = ((Boolean)result).booleanValue();
	}
	catch (Exception x) {printErreur(x, methode);}
	return resultat;
    }

    public Hashtable getStateBornes()
    {
	Hashtable resultat = null;
	final String methode = "getStateBornes";
	Vector v = new Vector();
	try
	{
	    Object result = client.execute(methode, v);
	    resultat = (Hashtable)result;
	}
	catch (Exception x) {printErreur(x, methode);}
	return resultat;

    }

    public void eclairageAllBornes(boolean on)
    {
	final String methode = "eclairageAllBornes";
	Vector v = new Vector();
	v.addElement(new Boolean(on));
	try
	{
	    Object result = client.execute(methode, v);
	    if (result == null) throw new Exception("pas de réponse");
	}
	catch (Exception x) {printErreur(x, methode);}
    }

    public void processAlarme(boolean on)
    {
	final String methode = "processAlarme";
	Vector v = new Vector();
	v.addElement(new Boolean(on));
	try
	{
	   Object result = client.execute(methode, v);
	   if (result == null) throw new Exception("pas de réponse");
	}
	catch (Exception x) {printErreur(x, methode);}
    }

    public void appelGardien(int numBorne, boolean on)
    {
	final String methode = "appelGardien";
	Vector v = new Vector();
	v.addElement(new Integer(numBorne));
	v.addElement(new Boolean(on));
	try
	{
	   Object result = client.execute(methode, v);
	   if (result == null) throw new Exception("pas de réponse");
	}
	catch (Exception x) {printErreur(x, methode);}
    }

    public void afficheMessage(int numBorne, String message)
    {
	final String methode = "afficheMessage";
	Vector v = new Vector();
	v.addElement(new Integer(numBorne));
	v.addElement(message);
	try
	{
	   Object result = client.execute(methode, v);
	   if (result == null) throw new Exception("pas de réponse");
	}
	catch (Exception x) {printErreur(x, methode);}
    }

    public void autoriseEntree(int numBorne)
    {
	final String methode = "autoriseEntree";
	Vector v = new Vector();
	v.addElement(new Integer(numBorne));
	try
	{
	   Object result = client.execute(methode, v);
	   if (result == null) throw new Exception("pas de réponse");
	}
	catch (Exception x) {printErreur(x, methode);}
    }

    public void defautBorne(boolean on, int numBorne, String codeDefaut)
    {
	final String methode = "defautBorne";
	Vector v = new Vector();
	v.addElement(new Boolean(on));
	v.addElement(new Integer(numBorne));
	v.addElement(codeDefaut);
	try
	{
	   Object result = client.execute(methode, v);
	   if (result == null) throw new Exception("pas de réponse");
	}
	catch (Exception x) {printErreur(x, methode);}
    }

    private final void printErreur(final Exception x, final String methode)
    {
	System.err.println("Execution de la méthode: " + methode +
	" impossible sur la borne dont l'url est: " + urlSuperviseur + "  [" + x.toString() + "]");
    }


    public boolean canExit()
    {
	return false;
    }

    public void exit(int level)
    {

    }

}